package test

import (
	"fmt"
	"math"
	"math/rand"
	"time"

	"b2c-delivery-optimization/internal/model"
	"b2c-delivery-optimization/internal/services"

	"gorm.io/gorm"
)

func init() {
	// 使用当前时间作为随机数种子
	rand.Seed(time.Now().UnixNano())
}

// ExperimentParams 定义实验参数
type ExperimentParams struct {
	OrderCount       int     // 订单总数
	MaxOrdersPerWave int     // 每个波次的最大订单数
	PriorityWeight   float64 // 优先级权重
	LocationWeight   float64 // 位置权重
}

// ExperimentResult 定义实验结果
type ExperimentResult struct {
	TotalWaves           int           // 总波次数
	AverageWaveSize      float64       // 平均波次大小
	ProcessingTime       time.Duration // 处理时间
	AverageDistance      float64       // 平均配送距离
	PrioritySatisfaction float64       // 优先级满足度
}

// ExperimentRunner 实验运行器
type ExperimentRunner struct {
	db           *gorm.DB
	waveService  *services.WaveService
	orderService *services.OrderService
}

// NewExperimentRunner 创建新的实验运行器
func NewExperimentRunner(db *gorm.DB) *ExperimentRunner {
	return &ExperimentRunner{
		db:           db,
		waveService:  services.NewWaveService(db),
		orderService: services.NewOrderService(),
	}
}

// clearDatabase 清除数据库中的所有测试数据
func (r *ExperimentRunner) clearDatabase() error {
	// 清除波次订单关联
	if err := r.db.Exec("DELETE FROM wave_orders").Error; err != nil {
		return fmt.Errorf("清除波次订单关联失败: %w", err)
	}

	// 清除波次
	if err := r.db.Exec("DELETE FROM waves").Error; err != nil {
		return fmt.Errorf("清除波次失败: %w", err)
	}

	// 清除订单
	if err := r.db.Exec("DELETE FROM orders").Error; err != nil {
		return fmt.Errorf("清除订单失败: %w", err)
	}

	return nil
}

// RunExperiment 运行实验
func (r *ExperimentRunner) RunExperiment(params ExperimentParams) (*ExperimentResult, error) {
	// 清除历史数据
	if err := r.clearDatabase(); err != nil {
		return nil, fmt.Errorf("清除历史数据失败: %w", err)
	}

	// 1. 生成测试订单并保存到数据库
	orderIDs, err := r.generateAndSaveTestOrders(params.OrderCount)
	if err != nil {
		return nil, fmt.Errorf("生成测试订单失败: %w", err)
	}
	// 记录实验开始时间
	startTime := time.Now()

	// 2. 分配订单到波次
	err = r.waveService.AllocateOrdersToWaves(orderIDs, params.MaxOrdersPerWave)
	if err != nil {
		return nil, fmt.Errorf("分配订单到波次失败: %w", err)
	}

	// 3. 计算处理时间
	processingTime := time.Since(startTime)

	// 4. 获取分配后的波次
	waves, _, err := r.waveService.ListWaves(&model.WaveQuery{
		Page:         1,
		PageSize:     1000,      // 设置较大的页面大小以获取所有波次
		CreatedAfter: startTime, // 只获取本次实验创建的波次
	})
	if err != nil {
		return nil, fmt.Errorf("获取波次列表失败: %w", err)
	}

	// 打印波次信息，用于调试
	fmt.Printf("数据库中的波次数: %d\n", len(waves))

	// 5. 计算实验结果
	result := &ExperimentResult{
		TotalWaves:      len(waves),
		AverageWaveSize: float64(len(orderIDs)) / float64(len(waves)),
		ProcessingTime:  processingTime,
	}

	// 6. 计算平均配送距离和优先级满足度
	totalDistance := 0.0
	totalPriority := 0
	totalOrders := 0
	waveCount := 0
	for _, wave := range waves {
		// 获取波次中的订单
		waveOrders, err := r.waveService.GetWave_Orders(wave.ID)
		if err != nil {
			fmt.Printf("获取波次 %s 的订单失败: %v\n", wave.ID, err)
			continue
		}
		if len(waveOrders) == 0 {
			continue
		}
		// 计算波次内订单的平均距离
		waveDistance := r.calculateWaveDistance(waveOrders)
		totalDistance += waveDistance

		// 累加所有订单的优先级
		for _, wo := range waveOrders {
			var order model.Order
			if err := r.db.First(&order, "id = ?", wo.OrderID).Error; err != nil {
				fmt.Printf("获取订单 %s 失败: %v\n", wo.OrderID, err)
				continue
			}
			totalPriority += order.Priority
			totalOrders++
		}
		waveCount++
	}

	if waveCount > 0 {
		result.AverageDistance = totalDistance / float64(waveCount)
		if totalOrders > 0 {
			// 计算所有订单的平均优先级
			averagePriority := float64(totalPriority) / float64(totalOrders)
			fmt.Printf("\n优先级统计:\n")
			fmt.Printf("总优先级: %d\n", totalPriority)
			fmt.Printf("总订单数: %d\n", totalOrders)
			fmt.Printf("平均优先级: %.2f\n", averagePriority)

			// 优先级满足度计算
			// 1是最低优先级，5是最高优先级
			// 将平均优先级映射到0-100的范围
			satisfaction := ((averagePriority - 1.0) / (5.0 - 1.0)) * 100.0
			fmt.Printf("\n优先级满足度计算:\n")
			fmt.Printf("计算公式: ((%.2f - 1.0) / (5.0 - 1.0)) * 100\n", averagePriority)
			fmt.Printf("计算结果: %.2f%%\n", satisfaction)

			// 确保结果在0-100之间
			if satisfaction > 100.0 {
				satisfaction = 100.0
			} else if satisfaction < 0.0 {
				satisfaction = 0.0
			}

			// 直接赋值计算结果
			result.PrioritySatisfaction = satisfaction
		}
	}

	return result, nil
}

// generateAndSaveTestOrders 生成测试订单并保存到数据库
func (r *ExperimentRunner) generateAndSaveTestOrders(count int) ([]string, error) {
	orderIDs := make([]string, 0, count)
	for i := 0; i < count; i++ {
		// 生成随机优先级 (1-5)
		// 使用更均匀的分布，确保优先级在1-5之间
		priority := rand.Intn(5) + 1
		// 生成随机位置坐标
		x := rand.Float64() * 100
		y := rand.Float64() * 100

		// 使用时间戳和随机数生成唯一订单ID
		timestamp := time.Now().UnixNano()
		randomNum := rand.Intn(1000000)
		orderID := fmt.Sprintf("TEST_ORD_%d_%d", timestamp, randomNum)

		order := &model.Order{
			ID:                orderID,
			DeliveryStationID: fmt.Sprintf("STATION_%d", i%5), // 5个配送站
			Priority:          priority,
			Location: model.Location{
				Latitude:  x,
				Longitude: y,
			},
			Status:      model.OrderStatusPending,
			CreateTime:  time.Now(),
			ReleaseTime: time.Now(),
		}
		// 保存订单到数据库
		if err := r.orderService.CreateOrder(order); err != nil {
			return nil, fmt.Errorf("保存订单失败: %w", err)
		}
		orderIDs = append(orderIDs, order.ID)
	}

	return orderIDs, nil
}

// calculateWaveDistance 计算波次内订单的平均距离
func (r *ExperimentRunner) calculateWaveDistance(waveOrders []model.WaveOrder) float64 {
	if len(waveOrders) <= 1 {
		return 0
	}
	// 获取订单位置信息
	orderLocations := make(map[string]model.Location)
	for _, wo := range waveOrders {
		var order model.Order
		if err := r.db.First(&order, "id = ?", wo.OrderID).Error; err != nil {
			fmt.Printf("获取订单 %s 失败: %v\n", wo.OrderID, err)
			continue
		}
		orderLocations[wo.OrderID] = order.Location
	}
	totalDistance := 0.0
	count := 0
	// 计算订单之间的距离
	orderIDs := make([]string, 0, len(waveOrders))
	for _, wo := range waveOrders {
		orderIDs = append(orderIDs, wo.OrderID)
	}

	for i := 0; i < len(orderIDs); i++ {
		for j := i + 1; j < len(orderIDs); j++ {
			loc1, ok1 := orderLocations[orderIDs[i]]
			loc2, ok2 := orderLocations[orderIDs[j]]
			if !ok1 || !ok2 {
				continue
			}
			// 计算欧几里得距离
			dx := loc1.Longitude - loc2.Longitude
			dy := loc1.Latitude - loc2.Latitude
			distance := math.Sqrt(dx*dx + dy*dy)
			// 将距离转换为公里（由于坐标是随机生成的，范围在0-100之间）
			// 使用0.05作为转换系数，使结果更合理
			distanceKm := distance * 0.05
			totalDistance += distanceKm
			count++
		}
	}
	if count == 0 {
		return 0
	}
	return totalDistance / float64(count)
}
